#pragma once

#include "base.h"
#include "../impl/misc.h"

namespace mdtx::online::updater
{
    template <typename T>
    class lindecay : public updater_unary1<T>,
                     public impl::lindecay<T>
    {
        using base = updater_unary1<T>;
        using ibase = impl::lindecay<T>;

    public:
        using typename base::tuple_in;
        using typename base::tuple_out;
        using base::insert;
        using base::remove;

        using ibase::ibase;
        using ibase::insert_impl;
        using ibase::reset_impl;

        void insert(tuple_in const &in) override
        {
            insert_impl(std::get<0>(in));
        }

        void reset() override
        {
            reset_impl();
        }

        tuple_out get() override
        {
            return tuple_out(this->decay);
        }
    };

    template <typename T>
    class expdecay : public updater_unary1<T>,
                     public impl::expdecay<T>
    {
        using base = updater_unary1<T>;
        using ibase = impl::expdecay<T>;

    public:
        using typename base::tuple_in;
        using typename base::tuple_out;
        using base::insert;
        using base::remove;

        using ibase::ibase;
        using ibase::insert_impl;
        using ibase::reset_impl;

        void insert(tuple_in const &in) override
        {
            insert_impl(std::get<0>(in));
        }

        void reset() override
        {
            reset_impl();
        }

        tuple_out get() override
        {
            return tuple_out(this->decay);
        }
    };

    template <typename T>
    class logret : public updater_unary1<T>,
                   public impl::logret<T>
    {
        using base = updater_unary1<T>;
        using ibase = impl::logret<T>;

    public:
        using typename base::tuple_in;
        using typename base::tuple_out;
        using base::insert;
        using base::remove;

        using ibase::insert_impl;
        using ibase::reset_impl;

        void insert(tuple_in const &in) override
        {
            insert_impl(std::get<0>(in));
        }

        void reset() override
        {
            reset_impl();
        }

        tuple_out get() override
        {
            return tuple_out(this->ret);
        }
    };

    template <typename T>
    class linret : public updater_unary1<T>,
                   public impl::linret<T>
    {
        using base = updater_unary1<T>;
        using ibase = impl::linret<T>;

    public:
        using typename base::tuple_in;
        using typename base::tuple_out;
        using base::insert;
        using base::remove;

        using ibase::insert_impl;
        using ibase::reset_impl;

        void insert(tuple_in const &in) override
        {
            insert_impl(std::get<0>(in));
        }

        void reset() override
        {
            reset_impl();
        }

        tuple_out get() override
        {
            return tuple_out(this->ret);
        }
    };

    template <typename T>
    class absret : public updater_unary1<T>,
                   public impl::absret<T>
    {
        using base = updater_unary1<T>;
        using ibase = impl::absret<T>;

    public:
        using typename base::tuple_in;
        using typename base::tuple_out;
        using base::insert;
        using base::remove;

        using ibase::insert_impl;
        using ibase::reset_impl;

        void insert(tuple_in const &in) override
        {
            insert_impl(std::get<0>(in));
        }

        void reset() override
        {
            reset_impl();
        }

        tuple_out get() override
        {
            return tuple_out(this->ret);
        }
    };
}
